package com.jbm.core.common;

import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;


/**
 * Created by root on 16-10-16.
 */
public class Resource
{
	public Resource ( int count, String resname )
	{
		m_count = count;
		m_resource = new ArrayBlockingQueue(count);

		for ( Integer i = 0; i < count; i ++ )
			m_resource.add(count-i-1);
		m_lifes = new Life[count];
		m_lifemap = new HashMap<String, Object>();

		m_lifethread = new LifeThread();
		m_lifethread.start();

		m_resname = resname;
	}

	protected int m_count;
	protected BlockingQueue m_resource;
	protected Life[] m_lifes;
	protected HashMap<String,Object> m_lifemap;

	private LifeThread m_lifethread = null;
	private final Object m_life_mutex = new Object();

	private String m_resname;

	private class LifeThread extends Thread
	{
		@Override
		public void run()
		{
			int i = 0;
			int sleeptimes = 0;
			boolean sleep = false;

			while(true)
			{
				if ( i >= m_count )
				{
					i = 0;

					if (sleeptimes==0)
						try
						{
							sleep(5);
						} catch (Exception e)
						{

						}

					sleeptimes = 0;
				}

				synchronized (m_life_mutex)
				{
					if ( m_lifes[i] != null )
					{
						try
						{
							m_lifes[i].Wakeup();
							sleep = true;
						} catch (Exception e)
						{

						}
					}
				}

				if ( sleep )
				{
					sleep = false;
					try
					{
						sleep(5);
						sleeptimes++;
					} catch (Exception e)
					{

					}
				}
				i++;
			}
		}
	}

	protected void putlifemap ( Object[] uidx, int index )
	{
		if ( uidx != null )
		{
			HashMap<String,Object> lm = m_lifemap;
			for (int i = 0; i < uidx.length; i++)
			{
				if ( i == uidx.length - 1 )
					lm.put(uidx[i].toString(), (Integer)index);
				else
				{
					HashMap<String,Object> lt = (HashMap<String,Object>)lm.get(uidx[i].toString());
					if ( lt == null )
					{
						lt = new HashMap<String, Object>();
						lm.put(uidx[i].toString(),lt);
					}

					lm = lt;
				}
			}
		}
	}

	protected Object getlifemap(Object[] uidx)
	{
		Integer idx = null;

		if ( uidx.length > 0 )
		{
			HashMap<String,Object> lm = m_lifemap;
			for (int i = 0; i < uidx.length; i++)
			{
				if ( i == uidx.length - 1 )
					return (Integer) lm.get(uidx[i].toString());
				else
				{
					HashMap<String,Object> lt = (HashMap<String,Object>)lm.get(uidx[i].toString());
					if ( lt == null )
						break;
					else
						lm = lt;
				}
			}
		}

		return idx;
	}

	protected void removelifemap(Object[] uidx)
	{
		if ( uidx != null )
		{
			HashMap<String,Object> lm = m_lifemap;
			for (int i = 0; i < uidx.length; i++)
			{
				if ( i == uidx.length - 1 )
					lm.remove(uidx[i].toString());
				else
				{
					HashMap<String,Object> lt = (HashMap<String,Object>)lm.get(uidx[i].toString());
					if ( lt == null )
						break;
					else
						lm = lt;
				}
			}
		}
	}

	public boolean ReAdd (Life life, Object... oldkey )
	{
		synchronized (m_life_mutex)
		{
			ResKey key = life.GetLifeName();

			removelifemap(oldkey);

			putlifemap(life.GetUniqueIndex(),key.index);
		}

		return true;
	}

	public boolean Add (Life life)
	{
		int index;

		try
		{
			index = (Integer) m_resource.take();
		}catch (Exception e)
		{
			return false;
		}

		synchronized (m_life_mutex)
		{
			ResKey key = new ResKey( index );
			life.BindLifeName( key );

			m_lifes[index] = life;
			life.SetStatus( Life.life_status_inqueue );

			putlifemap(life.GetUniqueIndex(),index);
		}

		life.BindPool( this );
		return true;
	}

	public boolean Drop ( ResKey key )
	{
		if ( key == null || key.index < 0 || key.key == null )
			return false;

		boolean back = false;

		synchronized (m_life_mutex)
		{
			if (m_lifes[key.index] != null)
				if (key.key.equals(m_lifes[key.index].GetLifeName().key))
				{
					removelifemap(m_lifes[key.index].GetUniqueIndex());
					m_lifes[key.index].SetStatus(Life.life_status_leftqueue);
					m_lifes[key.index] = null;

					back = true;
				}
		}

		if ( back )
			try
			{
				m_resource.put(key.index);
			}catch (Exception e)
			{
				return false;
			}

		return true;
	}

	public Life Get (ResKey key, Object result, Object... uniqueidx )
	{
		if ( ( uniqueidx.length == 0 || uniqueidx[0] == null ) &&
				( key == null || key.index < 0 || key.key == null ) )
			return null;

		synchronized (m_life_mutex)
		{
			if ( uniqueidx.length > 0 && uniqueidx[0] != null )
			{
				Integer index = (Integer)getlifemap(uniqueidx);

				if ( index != null )
					return m_lifes[index];
				else
					return null;
			}else if ( m_lifes[key.index] != null )
				if ( key.key.equals(m_lifes[key.index].GetLifeName().key))
				{
					Life rtn = m_lifes[key.index];
					int rmark = rtn.IsLast(result);
					if ( rmark == 1 )
						Drop( key );
					else if ( rmark == 2 )
						rtn.Die();
					return rtn;
				}else
					return null;
			else
				return null;
		}
	}

	public Life GetorAdd (ResKey key, Object result, boolean doadd, Life life, Object... uniqueidx )
	{
		synchronized (m_life_mutex)
		{
			Life lf = Get(key,result,uniqueidx);

			if ( lf == null && doadd )
			{
				Add(life);
				return life;
			}else
				return lf;
		}
	}
}
